package com.yumei.trader.gym.view;


import com.yumei.trader.gym.view.element.StockHisObject;
import com.yumei.trader.gym.view.element.TicketElement;

import java.util.ArrayList;

public class AnalyzeManager {

	private static AnalyzeManager instance;

	public static AnalyzeManager getInstance(){

		if(instance == null){
			instance = new AnalyzeManager();
		}
		return instance;
	}

	public void analyzeIndex(StockHisObject stock, StockRequest req){

		if(stock == null) return;

		for(int i = 0; i< StockRequest.indexs.length; i++){

			switch(StockRequest.indexs[i]){

				case StockConst.Index_Up_MA:  //MA
					MA(stock,req.ma[0],req.ma[1],req.ma[2],req.ma[3]);
					break;
				case StockConst.Index_Down_MACD:    //MACD
					MACD(stock,req.macd);
					break;
				case StockConst.Index_Down_RSI:  //RSI
					RSI(stock,req.rsi[0],req.rsi[1],req.rsi[2]);
					break;
				case StockConst.Index_Down_DMI:  //DMI
					DMI(stock);
					break;
				case StockConst.Index_Up_SAR:  //SAR
					SAR(stock, req.sar, 0.2f);
					break;
				case StockConst.Index_Up_BOLL:  //BOLL
					BollingerBands(stock,req.boll);
					break;
				case StockConst.Index_Down_KDJ:   //KDJ
					KDJ(stock,req.kdj);
					break;
				default:
					break;
			}
		}
	}





	/*************************************************************************************
	 * MA(N)
	 * @param stock
	 * @param ma1
	 * @param ma2
	 *************************************************************************************/
	public void MA(StockHisObject stock, int ma1, int ma2, int ma3, int ma4){

		if(stock ==null) return;


		int size = stock.tickets.size();

		if(ma1>0) {
			for(int i = (ma1-1) ;i<size;i++){
				TicketElement temp = stock.tickets.get(i);
				temp.MA5 = AVG(stock.tickets,i,ma1);
			}
		}

		if(ma2>0) {
			for(int i = (ma2-1) ;i<size;i++){
				TicketElement temp = stock.tickets.get(i);
				temp.MA10 = AVG(stock.tickets,i,ma2);
			}
		}

		if(ma3>0) {
			for(int i = (ma3-1) ;i<size;i++){
				TicketElement temp = stock.tickets.get(i);
				temp.MA20 = AVG(stock.tickets,i,ma3);
			}
		}

		if(ma4>0) {
			for(int i = (ma4-1) ;i<size;i++){
				TicketElement temp = stock.tickets.get(i);
				temp.MA30 = AVG(stock.tickets,i,ma4);
			}
		}
	}


	private float AVG(ArrayList<TicketElement> ticks, int index, int N){

		float sum = 0.0f;
		for(int j= 0;j< N;j++){
			sum += ticks.get(index-j).close;
		}
		return  sum/N;
	}


	/***********************************************************************************
	 * MACD
	 * @param stock
	 * @param param
	 ***********************************************************************************/

	public void MACD(StockHisObject stock, int[] param){

		int len = stock.tickets.size();

		float EMA12 = stock.tickets.get(0).close;
		float EMA26 = stock.tickets.get(0).close;

		float a12 = 2.0f/(param[0]+1);
		float a26 = 2.0f/(param[1]+1);
		float a9 = 2.0f/(param[2]+1);

		float[] DIF = new float[len];
		float[] DEA = new float[len];
		float[] MACD = new float[len];


		for(int i= 0 ; i<len; i++){

			TicketElement tick = stock.tickets.get(i);

			EMA12 = (tick.close - EMA12)*a12+EMA12;
			EMA26 = (tick.close - EMA26)*a26+EMA26;

			tick.DIF = EMA12 - EMA26;
			//DIF[i] = EMA12 - EMA26;

			if(i== 0){
				tick.DEA = tick.DIF;
			}else{
				TicketElement temp = stock.tickets.get(i-1);
				tick.DEA = (tick.DIF - temp.DEA)*a9+temp.DEA;
			}

			tick.MACD = tick.DIF-tick.DEA;

			//System.out.println("date ="+stock.mHisDataDayTicks[i].date+" DIF["+i+"] = "+DIF[i]+", MACD["+i+"]="+MACD[i]);
		}
	}

	/***********************************************************************************
	 * RSI
	 * @param stock
	 * @param N1 = 6,12,24
	 ***********************************************************************************/

	public void RSI(StockHisObject stock, int N1, int N2, int N3){

		int len = stock.tickets.size();

		float rs = 0.0f;

		for (int i = N1; i < len; i++) {
			TicketElement ticket = stock.tickets.get(i);
			rs = RS(stock.tickets, i, N1);
			ticket.RSI1 = 100 - 100 / (1 + rs);
			System.out.println("RSI1="+ticket.RSI1);
		}


		for (int i = N2; i < len; i++) {
			TicketElement ticket = stock.tickets.get(i);
			rs = RS(stock.tickets, i, N2);
			ticket.RSI2 = 100 - 100 / (1 + rs);
		}


		for (int i = N3; i < len; i++) {
			TicketElement ticket = stock.tickets.get(i);
			rs = RS(stock.tickets, i, N3);
			ticket.RSI3 = 100 - 100 / (1 + rs);
		}

	}

	/**
	 * RS
	 * @param ticks
	 * @param index
	 * @param N
	 * @return
	 */
	private float RS(ArrayList<TicketElement> ticks, int index, int N){

		float upSum = 0.0f;

		float downSum = 0.0f;

		for(int i=0;i<(N-1);i++){

			TicketElement ticket = ticks.get(index-i);
			TicketElement temp = ticks.get(index-i-1);

			if(ticket.close > temp.close){
				upSum += (ticket.close-temp.close);
				System.out.println(ticket.date+":"+ticket.close+"-"+temp.close+"="+(ticket.close-temp.close));
			}else{
				downSum += (temp.close-ticket.close);
				System.out.println(ticket.date+":"+ticket.close+"-"+temp.close+"="+(ticket.close-temp.close));
			}
		}

		System.out.println("up="+upSum+",down="+downSum);
		return (upSum/downSum);
	}





	/*********************************************************************************
	 * DMI
	 * @param stock
	 **********************************************************************************/

	public void DMI(StockHisObject stock){

		int len = stock.tickets.size();

		float a14 = 2.0f/(14+1);
		float a6 = 2.0f/(6+1);

		float ETR = 0.0f;
		float EDM0 = 0.0f;
		float EDM1 = 0.0f;

		int start = 1;

		for(int i= 1 ; i<len; i++){
			float[] DM =DM(stock.tickets,i);
			if(DM[0] != 0.0f || DM[1] != 0.0f){
				start = i;
				break;
			}
		}


		for(int i= start ; i<len; i++){

			float[] DM =DM(stock.tickets,i);
			if(i == start){
				ETR  = TR(stock.tickets,i);
				EDM0 = DM[0];
				EDM1 = DM[1];
			}else{
				ETR =  (TR(stock.tickets,i) - ETR)*a14+ETR;
				EDM0 = (DM[0] - EDM0)*a14+EDM0;
				EDM1 = (DM[1] - EDM1)*a14+EDM1;
			}

			TicketElement ticket = stock.tickets.get(i);
			TicketElement temp = stock.tickets.get(i-1);

			ticket.PDI = 100*EDM0/ETR;
			ticket.MDI = 100*EDM1/ETR;

			ticket.DX = 100*(Math.abs(ticket.PDI - ticket.MDI)) / (ticket.PDI + ticket.MDI);

			if(i== start){
				ticket.ADX = ticket.DX;
			}else{
				ticket.ADX = (ticket.DX - temp.ADX)*a6+temp.ADX;
			}

			System.out.println("date ="+ticket.date +"/code "+stock.code+" MDI+["+i+"] = "+ticket.PDI+" MDI-["+i+"] = "+ticket.MDI+" DX+["+i+"] = "+ticket.DX+" ADX+["+i+"] = "+ticket.ADX);
		}
	}


	/**
	 * TR
	 * @param ticks
	 * @param index
	 * @return
	 */
	private float TR(ArrayList<TicketElement> ticks,int index){

		float HL = ticks.get(index).high -  ticks.get(index).low;
		float LC = Math.abs( ticks.get(index).low - ticks.get(index-1).close);
		float HC = Math.abs( ticks.get(index).high - ticks.get(index-1).close);

		if(HL > LC){
			return (HL > HC)?HL:HC;
		}else{
			return (LC > HC)?LC:HC;
		}
	}


	/**
	 *  DM
	 * @param ticks
	 * @param index
	 * @return
	 */

	private float[] DM(ArrayList<TicketElement> ticks,int index){

		float[] DM = new float[]{0.0f,0.0f};

		float A = ticks.get(index).high - ticks.get(index-1).high;
		float B = ticks.get(index).low - ticks.get(index-1).low;

		if(A > 0  && B >=0){
			DM[0] = A;
			DM[1] = 0.0f;
		}else if(A <=0 && B <0){
			DM[0] = 0;
			DM[1] = -B;
		}else if(A >0 && B <0){

			if(A > -B){
				DM[0] = A;
				DM[1] = 0;
			}else{
				DM[0] =0;
				DM[1] = -B;
			}
		}else{
			DM[0] = 0.0f;
			DM[1] = 0.0f;
		}

		return DM;
	}



	/*********************************************************************************
	 * SAR
	 * @param stock
	 * @param speed
	 * @param max
	 *********************************************************************************/

	public void SAR(StockHisObject stock, float speed, float max){

		int len = stock.tickets.size();
		float temp = 0.0f;
		float AF = speed;
		float EP = 0.0f;

		if(len<2) return;

		boolean upMove = false;

		int[] point = startPoint(stock.tickets,1);

		TicketElement tick1 = stock.tickets.get(point[1]);
		TicketElement tick0 = stock.tickets.get(point[1]-1);

		if(point[0] == 1){
			upMove = true;
			EP = tick1.high;
			tick1.SAR = tick0.low;
		}else{
			upMove = false;
			EP = tick1.low;
			tick1.SAR = tick0.high;
		}


		for(int i=point[1]+1;i<len;i++){

			TicketElement cell = stock.tickets.get(i);
			TicketElement pcell = stock.tickets.get(i-1);


			if(upMove){
				if(cell.high >EP){
					EP = cell.high;
					AF +=speed;
					if(AF >max){
						AF = max;
					}
				}

				temp = pcell.SAR +AF *(EP - pcell.SAR);

				if(temp > cell.low){
					upMove = false;
					cell.SAR = EP;
					AF = speed;
					EP = cell.low;
				}else{
					cell.SAR = temp;
				}
			}else{
				if(cell.low < EP){
					EP = cell.low;
					AF +=speed;
					if(AF >max){
						AF = max;
					}
				}
				temp = pcell.SAR +AF *(EP - pcell.SAR);

				if(temp < cell.high){
					upMove = true;
					cell.SAR = EP;
					EP = cell.high;
					AF = speed;
				}else{
					cell.SAR = temp;
				}
			}
		}
	}


	/**
	 * SAR
	 * @param ticks
	 * @param index
	 * @return point[0]: (1:��,0:��) ,point[1]:�������
	 */
	private int[] startPoint(ArrayList<TicketElement> ticks,int index){

		int[] point = null;

		TicketElement preEl = ticks.get(index-1);
		TicketElement el = ticks.get(index);

		if((el.high > preEl.high) && (el.low > preEl.low)){
			point = new int[2];
			point[0] = 1;
			point[1] = index;
		}else if((el.high < preEl.high) && (el.low < preEl.low)){
			point = new int[2];
			point[0] = 0;
			point[1] = index;
		}else if((el.high < preEl.high) && (el.low > preEl.low)){
			point = new int[2];
			point[0] = 1;
			point[1] = index;
		}else{
			return startPoint(ticks,index+1);
		}
		return point;
	}



	/*************************************************************************************
	 * Bollinger Bands
	 * @param stock
	 * @param N =20
	 * @return
	 ************************************************************************************/

	public void BollingerBands(StockHisObject stock, int N){

		int len = stock.tickets.size();


		for(int i = N-1 ;i<len;i++){

			TicketElement ticket = stock.tickets.get(i);

			ticket.M_Boll = AVG(stock.tickets,i,N);

			ticket.U_Boll = ticket.M_Boll + standard(stock.tickets,ticket.M_Boll,i,N)*2;

			ticket.L_Boll = ticket.M_Boll - standard(stock.tickets,ticket.M_Boll,i,N)*2;

			// System.out.println(stock.mHisDataDayTicks[i].date + " Up_Band:"+U_Band[i]+" M_Band ="+M_Band[i]+" L_Band="+L_Band[i]);
		}
	}


	/**
	 * @param ticks
	 * @param MA
	 * @param index
	 * @param N
	 * @return float
	 */
	private float standard(ArrayList<TicketElement> ticks,float MA ,int index,int N){

		double sum = 0.0f;
		for(int i= 0;i< N;i++){
			sum +=Math.pow((ticks.get(index-i).close - MA),2);
		}
		return  (float)(Math.sqrt(sum/(N-1)));

	}



	/*************************************************************************************
	 * KDJ
	 * @param stock
	 * @param N = 9
	 * @return
	 ************************************************************************************/

	public void KDJ(StockHisObject stock, int N){

		int len = stock.tickets.size();

		float RSV = 0.0f;
		float[] value = null;

		if(len < N) return;


		TicketElement ticket = stock.tickets.get(N-1);
		ticket.Kn = 50;
		ticket.Dn = 50;

		for(int i = N;i<len;i++){
			value = LowOrHigh(stock.tickets,i,N);

			TicketElement temp = stock.tickets.get(i);
			TicketElement ptemp = stock.tickets.get(i-1);

			RSV = (temp.close - value[0])*100/(value[1] - value[0]);

			temp.Kn = 2*ptemp.Kn/3.0f +RSV/3.0f;
			temp.Dn = 2*ptemp.Dn/3.0f + temp.Kn/3.0f;
			temp.Jn = 3*temp.Kn - 2*temp.Dn;
		}
	}



	/**
	 * @param ticks
	 * @param index
	 * @param N
	 * @return 0:low, 1:high
	 */
	private float[] LowOrHigh(ArrayList<TicketElement> ticks,int index,int N){
		float[] value = new float[2];

		value[0] = ticks.get(index).low;
		value[1] = ticks.get(index).high;

		for(int i=1;i<N;i++){

			value[0] = Math.min(ticks.get(index-i).low, value[0]);
			value[1] = Math.max(ticks.get(index-i).high, value[1]);
		}

		return value;
	}





}
